using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    interface IGameControllerCaller
    {
        ServerMessage CallGameController(GameController server);
    }

    abstract class ClientMessage
    {
        protected delegate Dictionary<PlayingPiece, int> GameControllerAssignLossesCallback(GameController server);
        protected delegate bool GameControllerBoolCallback(GameController server);
        protected delegate List<DeploymentMove> GameControllerDeploymentMovesCallback(GameController server);
        protected delegate GameController.defenderOptions GameControllerDefenderOptionsCallback(GameController server);
        protected delegate List<OperationalMove> GameControllerListOpMovesCallback(GameController server);
        protected delegate Dictionary<MapInfo.CountryID, int> GameControllerGSUCombatCasualtiesCallback(GameController server);
        protected delegate GameController.defenderCounterAttackOptions GameControllerDefenderCounterAttackCallback(GameController server);
        protected TCPServer.ServerRequestMessage serverMessageToReturn;
        public abstract System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml);

        public TCPServer.ServerRequestMessage ServerMessageToReturn
        {
            get
            {
                return serverMessageToReturn;
            }
        }

        public static ClientMessage Deserialise(System.Xml.XmlNode node)
        {
            if (node.Name == "ClientMessage")
            {
                switch (node.Attributes["ClientMessageType"].Value)
                {
                    case "AskForDefenderOptionsReturn":
                        return (ClientMessage)ClientMessageAskForDefenderOptionsReturn.Deserialise(node);
                    case "DoDefenderCombatReturn":
                        return (ClientMessage)ClientMessageDoDefenderCombatReturn.Deserialise(node);
                    case "AskAttackerToAssignLosses":
                        return (ClientMessage)ClientMessageAskAttackerToAssignLosses.Deserialise(node);
                    case "ClientMessageAssignLossesReturn":
                        return (ClientMessage)ClientMessageAssignLossesReturn.Deserialise(node);
                    case "ClientMessageDefenderCounterAttackOptionsReturn":
                        return (ClientMessage)ClientMessageDefenderCounterAttackOptionsReturn.Deserialise(node);
                    case "ClientMessageDoStrategicBombingWarfareReturn":
                        return (ClientMessage)ClientMessageDoStrategicBombingWarfareReturn.Deserialise(node);
                    case "ClientMessageDoStrategicUBoatWarfareReturn":
                        return (ClientMessage)ClientMessageDoStrategicUBoatWarfareReturn.Deserialise(node);
                    case "ClientMessageProductionMovesReturn":
                        return (ClientMessage)ClientMessageProductionMovesReturn.Deserialise(node);
                    case "ClientMessageBoolReturn":
                        return (ClientMessage)ClientMessageBoolReturn.Deserialise(node);
                    case "ClientMessageMovesReturn":
                        return (ClientMessage)ClientMessageMovesReturn.Deserialise(node);
                    case "ClientMessageAskForGSUCombatCasualtiesReturn":
                        return (ClientMessage)ClientMessageAskForGSUCombatCasualtiesReturn.Deserialise(node);
                    case "ClientMessageAskForBreakThroughOptionReturn":
                        return (ClientMessage)ClientMessageAskForBreakThroughOptionReturn.Deserialise(node);
                    case "ClientMessageDetermineStrategicWarInterception":
                        return (ClientMessage)ClientMessageDetermineStrategicWarInterception.Deserialise(node);
                    case "ClientMessageAskForNewCountryDeployment":
                        return (ClientMessage)ClientMessageAskForNewCountryDeployment.Deserialise(node);
                    case "ClientMessageAskForNavalInterception":
                        return (ClientMessage)ClientMessageAskForNavalInterception.Deserialise(node);
                    case "ClientMessageReportForNavalInterception":
                        return (ClientMessage)ClientMessageReportForNavalInterception.Deserialise(node);
                    case "ClientMessageAskDefenderForDefenderOptions":
                        return (ClientMessage)ClientMessageAskDefenderForDefenderOptions.Deserialise(node);
                    case "ClientMessageAskDefenderForRetreatBeforeCombatMoves":
                        return (ClientMessage)ClientMessageAskDefenderForRetreatBeforeCombatMoves.Deserialise(node);
                    case "ClientMessageAskForGSUCombatCasualties":
                        return (ClientMessage)ClientMessageAskForGSUCombatCasualties.Deserialise(node);
                    case "ClientMessageDoDefenderCombat":
                        return (ClientMessage)ClientMessageDoDefenderCombat.Deserialise(node);
                    case "ClientMessageDoDefenderBreakThroughCombat":
                        return (ClientMessage)ClientMessageDoDefenderBreakThroughCombat.Deserialise(node);
                    case "ClientMessageAskDefenderToAssignLosses":
                        return (ClientMessage)ClientMessageAskDefenderToAssignLosses.Deserialise(node);
                    case "ClientMessageAskDefenderForCounterAttack":
                        return (ClientMessage)ClientMessageAskDefenderForCounterAttack.Deserialise(node);
                }
            }

            throw new InvalidOperationException("Could not parse server message");
        }
    }

    class ClientMessageAskForDefenderOptionsReturn : ClientMessage
    {
        public GameController.defenderOptions defenderOptions;
        public ClientMessageAskForDefenderOptionsReturn(GameController.defenderOptions defenderOptions)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForDefenderOptionsReturn;
            this.defenderOptions = new GameController.defenderOptions();
            if (defenderOptions.defenderGSUSelections != null)
                this.defenderOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>(defenderOptions.defenderGSUSelections);
            else
                this.defenderOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();

            this.defenderOptions.defenderReinforceBattle = defenderOptions.defenderReinforceBattle;
            if (defenderOptions.defenderReinforceBattleMoves != null)
                this.defenderOptions.defenderReinforceBattleMoves = new List<OperationalMove>(defenderOptions.defenderReinforceBattleMoves);
            else
                this.defenderOptions.defenderReinforceBattleMoves = new List<OperationalMove>();
            this.defenderOptions.retreatBeforeCombat = defenderOptions.retreatBeforeCombat;
            if (defenderOptions.specialActionsSpentOnReinforcements != null)
                this.defenderOptions.specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>(defenderOptions.specialActionsSpentOnReinforcements);
            else
                this.defenderOptions.specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "AskForDefenderOptionsReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefenderGSUSelectionsNode = xml.CreateElement("DefenderGSUSelections");
            foreach (MapInfo.CountryID country in this.defenderOptions.defenderGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelectionNode");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defenderOptions.defenderGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefenderGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefenderGSUSelectionsNode);

            System.Xml.XmlNode DefenderReinforceBattleNode = xml.CreateElement("DefenderReinforceBattle");
            DefenderReinforceBattleNode.InnerText = this.defenderOptions.defenderReinforceBattle.ToString();
            nodeToReturn.AppendChild(DefenderReinforceBattleNode);

            System.Xml.XmlNode DefenderReinforceBattleMovesNode = xml.CreateElement("DefenderReinforceBattleMoves");
            foreach (OperationalMove opMove in this.defenderOptions.defenderReinforceBattleMoves)
            {
                System.Xml.XmlNode ReinforceBattleMoveNode = xml.CreateElement("ReinforceBattleMove");
                ReinforceBattleMoveNode.AppendChild(opMove.Serialise(xml));
                DefenderReinforceBattleMovesNode.AppendChild(ReinforceBattleMoveNode);
            }
            nodeToReturn.AppendChild(DefenderReinforceBattleMovesNode);

            System.Xml.XmlNode RetreatBeforeCombatNode = xml.CreateElement("RetreatBeforeCombat");
            RetreatBeforeCombatNode.InnerText = this.defenderOptions.retreatBeforeCombat.ToString();
            nodeToReturn.AppendChild(RetreatBeforeCombatNode);

            System.Xml.XmlNode SpecialActionsSpentOnReinforcementsNode = xml.CreateElement("SpecialActionsSpentOnReinforcements");
            foreach (MapInfo.CountryID country in this.defenderOptions.specialActionsSpentOnReinforcements.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode SpecialActionNode = xml.CreateElement("SpecialActionNode");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defenderOptions.specialActionsSpentOnReinforcements[country].ToString();
                SpecialActionNode.Attributes.Append(countryAttr);
                SpecialActionNode.Attributes.Append(numberAttr);
                SpecialActionsSpentOnReinforcementsNode.AppendChild(SpecialActionNode);
            }
            nodeToReturn.AppendChild(SpecialActionsSpentOnReinforcementsNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskForDefenderOptionsReturn Deserialise(System.Xml.XmlNode node)
        {
            GameController.defenderOptions defenderOptions = new GameController.defenderOptions();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefenderGSUSelections")
                {
                    defenderOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defenderOptions.defenderGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "DefenderReinforceBattle")
                    defenderOptions.defenderReinforceBattle = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefenderReinforceBattleMoves")
                {
                    defenderOptions.defenderReinforceBattleMoves = new List<OperationalMove>();
                    foreach (System.Xml.XmlNode OpMoveNode in childNode)
                    {
                        if(OpMoveNode.Name == "ReinforceBattleMove")
                        {
                            defenderOptions.defenderReinforceBattleMoves.Add((OperationalMove)OperationalMove.Deserialise(OpMoveNode.ChildNodes[0]));
                        }
                    }
                }
                if (childNode.Name == "RetreatBeforeCombat")
                    defenderOptions.retreatBeforeCombat = bool.Parse(childNode.InnerText);

                if (childNode.Name == "SpecialActionsSpentOnReinforcements")
                {
                    defenderOptions.specialActionsSpentOnReinforcements = new Dictionary<MapInfo.CountryID, int>();
                    foreach (System.Xml.XmlNode SpecialActionNode in childNode)
                    {
                        defenderOptions.specialActionsSpentOnReinforcements.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), SpecialActionNode.Attributes["country"].Value), Int32.Parse(SpecialActionNode.Attributes["number"].Value));
                    }
                }
            }

            return new ClientMessageAskForDefenderOptionsReturn(defenderOptions);
        }
    }

    class ClientMessageDoDefenderCombatReturn : ClientMessage
    {
        public Dictionary<PlayingPiece, int> defenderCombatReturn;
        public ClientMessageDoDefenderCombatReturn(Dictionary<PlayingPiece, int> defenderCombatReturn)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.DoDefenderCombatReturn;
            if (defenderCombatReturn != null)
                this.defenderCombatReturn = new Dictionary<PlayingPiece, int>(defenderCombatReturn);
            else
                this.defenderCombatReturn = new Dictionary<PlayingPiece, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "DoDefenderCombatReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefenderCombatReturnNode = xml.CreateElement("DefenderCombatReturn");
            foreach (PlayingPiece piece in this.defenderCombatReturn.Keys)
            {
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode CasualtyNode = xml.CreateElement("Casualty");
                numberAttr.Value = this.defenderCombatReturn[piece].ToString();
                if (piece is Block)
                    CasualtyNode.AppendChild(((Block)piece).Serialise(xml));
                else if (piece is GroundSupportUnit)
                    CasualtyNode.AppendChild(((GroundSupportUnit)piece).Serialise(xml));
                CasualtyNode.Attributes.Append(numberAttr);
                DefenderCombatReturnNode.AppendChild(CasualtyNode);
            }
            nodeToReturn.AppendChild(DefenderCombatReturnNode);

            return nodeToReturn;
        }

        public new static ClientMessageDoDefenderCombatReturn Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<PlayingPiece, int> defenderCombatReturn = new Dictionary<PlayingPiece, int>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefenderCombatReturn")
                {
                    foreach (System.Xml.XmlNode CasualtyNode in childNode)
                    {
                        defenderCombatReturn.Add(PlayingPiece.Deserialise(CasualtyNode.FirstChild), Int32.Parse(CasualtyNode.Attributes["number"].Value));
                    }
                }
            }

            return new ClientMessageDoDefenderCombatReturn(defenderCombatReturn);
        }
    }

    class ClientMessageAssignLossesReturn : ClientMessage
    {
        public Dictionary<PlayingPiece, int> losses;

        public ClientMessageAssignLossesReturn(Dictionary<PlayingPiece, int> losses)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AssignLossesReturn;
            if (losses != null)
                this.losses = new Dictionary<PlayingPiece, int>(losses);
            else
                this.losses = new Dictionary<PlayingPiece, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAssignLossesReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode LossesNode = xml.CreateElement("Losses");
            foreach (PlayingPiece piece in this.losses.Keys)
            {
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode CasualtyNode = xml.CreateElement("Casualty");
                numberAttr.Value = this.losses[piece].ToString();
                if (piece is Block)
                    CasualtyNode.AppendChild(((Block)piece).Serialise(xml));
                else if (piece is GroundSupportUnit)
                    CasualtyNode.AppendChild(((GroundSupportUnit)piece).Serialise(xml));
                CasualtyNode.Attributes.Append(numberAttr);
                LossesNode.AppendChild(CasualtyNode);
            }
            nodeToReturn.AppendChild(LossesNode);

            return nodeToReturn;
        }

        public new static ClientMessageAssignLossesReturn Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<PlayingPiece, int> losses = new Dictionary<PlayingPiece, int>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Losses")
                {
                    foreach (System.Xml.XmlNode CasualtyNode in childNode)
                    {
                        losses.Add(PlayingPiece.Deserialise(CasualtyNode.FirstChild), Int32.Parse(CasualtyNode.Attributes["number"].Value));
                    }
                }
            }

            return new ClientMessageAssignLossesReturn(losses);
        }
    };

    class ClientMessageDefenderCounterAttackOptionsReturn : ClientMessage
    {
        public GameController.defenderCounterAttackOptions counterAttackOptions;

        public ClientMessageDefenderCounterAttackOptionsReturn(GameController.defenderCounterAttackOptions counterAttackOptions)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.CounterAttackReturn;
            this.counterAttackOptions.assault = counterAttackOptions.assault;
            this.counterAttackOptions.defenderCounterAttacked = counterAttackOptions.defenderCounterAttacked;
            if (counterAttackOptions.defenderGSUSelections != null)
                this.counterAttackOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>(counterAttackOptions.defenderGSUSelections);
            else
                this.counterAttackOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (counterAttackOptions.listOfCounterAttackingMoves != null)
                this.counterAttackOptions.listOfCounterAttackingMoves = new List<MovePieceOperationalMove>(counterAttackOptions.listOfCounterAttackingMoves);
            else
                this.counterAttackOptions.listOfCounterAttackingMoves = new List<MovePieceOperationalMove>();
            if (counterAttackOptions.specialActionsSpent != null)
                this.counterAttackOptions.specialActionsSpent = new List<MapInfo.CountryID>(counterAttackOptions.specialActionsSpent);
            else
                this.counterAttackOptions.specialActionsSpent = new List<MapInfo.CountryID>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageDefenderCounterAttackOptionsReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = counterAttackOptions.assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefenderCounterAttackedNode = xml.CreateElement("DefenderCounterAttacked");
            DefenderCounterAttackedNode.InnerText = counterAttackOptions.defenderCounterAttacked.ToString();
            nodeToReturn.AppendChild(DefenderCounterAttackedNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.counterAttackOptions.defenderGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.counterAttackOptions.defenderGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode ListOfCounterAttackingMovesNode = xml.CreateElement("ListOfCounterAttackingMoves");
            foreach (MovePieceOperationalMove opMove in this.counterAttackOptions.listOfCounterAttackingMoves)
            {
                System.Xml.XmlNode CounterAttackMoveNode = xml.CreateElement("CounterAttackMove");
                CounterAttackMoveNode.AppendChild(opMove.Serialise(xml));
                ListOfCounterAttackingMovesNode.AppendChild(CounterAttackMoveNode);
            }
            nodeToReturn.AppendChild(ListOfCounterAttackingMovesNode);

            System.Xml.XmlNode SpecialActionsSpentNode = xml.CreateElement("SpecialActionsSpent");
            foreach (MapInfo.CountryID country in counterAttackOptions.specialActionsSpent)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                SpecialActionsSpentNode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(SpecialActionsSpentNode);

            return nodeToReturn;
        }

        public new static ClientMessageDefenderCounterAttackOptionsReturn Deserialise(System.Xml.XmlNode node)
        {
            GameController.defenderCounterAttackOptions counterAttackOptions = new GameController.defenderCounterAttackOptions();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Assault")
                    counterAttackOptions.assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefenderCounterAttacked")
                    counterAttackOptions.defenderCounterAttacked = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    counterAttackOptions.defenderGSUSelections = new Dictionary<MapInfo.CountryID, int>();
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        counterAttackOptions.defenderGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "ListOfCounterAttackingMoves")
                {
                    counterAttackOptions.listOfCounterAttackingMoves = new List<MovePieceOperationalMove>();
                    foreach (System.Xml.XmlNode OpMoveNode in childNode)
                    {
                        if (OpMoveNode.Name == "CounterAttackMove")
                        {
                            counterAttackOptions.listOfCounterAttackingMoves.Add((MovePieceOperationalMove)MovePieceOperationalMove.Deserialise(OpMoveNode.ChildNodes[0]));
                        }
                    }
                }
                if (childNode.Name == "SpecialActionsSpent")
                {
                    counterAttackOptions.specialActionsSpent = new List<MapInfo.CountryID>();
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            counterAttackOptions.specialActionsSpent.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
            }

            return new ClientMessageDefenderCounterAttackOptionsReturn(counterAttackOptions);
        }
    };

    class ClientMessageDoStrategicBombingWarfareReturn : ClientMessage
    {
        public List<StratWarfareMove> stratWarfareMoves;

        public ClientMessageDoStrategicBombingWarfareReturn(List<StratWarfareMove> stratWarfareMoves)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.StratWarfareReturn;
            if (stratWarfareMoves != null)
                this.stratWarfareMoves = new List<StratWarfareMove>(stratWarfareMoves);
            else
                this.stratWarfareMoves = new List<StratWarfareMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageDoStrategicBombingWarfareReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode StratWarfareMovesNode = xml.CreateElement("StratWarfareMoves");
            foreach (StratWarfareMove stratWarfareMove in stratWarfareMoves)
            {
                System.Xml.XmlNode StratWarfareMoveNode = xml.CreateElement("StratWarfareMove");
                StratWarfareMoveNode.AppendChild(stratWarfareMove.Serialise(xml));
                StratWarfareMovesNode.AppendChild(StratWarfareMoveNode);
            }
            nodeToReturn.AppendChild(StratWarfareMovesNode);

            return nodeToReturn;
        }

        public new static ClientMessageDoStrategicBombingWarfareReturn Deserialise(System.Xml.XmlNode node)
        {
            List<StratWarfareMove> stratWarfareMoves = new List<StratWarfareMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "StratWarfareMoves")
                {
                    foreach (System.Xml.XmlNode OpMoveNode in childNode)
                    {
                        if (OpMoveNode.Name == "StratWarfareMove")
                        {
                            stratWarfareMoves.Add((StratWarfareMove)StratWarfareMove.Deserialise(OpMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageDoStrategicBombingWarfareReturn(stratWarfareMoves);
        }
    };

    class ClientMessageDoStrategicUBoatWarfareReturn : ClientMessage
    {
        public StratWarfareMove stratWarfareMove;

        public ClientMessageDoStrategicUBoatWarfareReturn(StratWarfareMove stratWarfareMove)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.DoStrategicUBoatWarfareReturn;
            this.stratWarfareMove = stratWarfareMove;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageDoStrategicUBoatWarfareReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode StratWarfareMoveNode = xml.CreateElement("StratWarfareMove");
            StratWarfareMoveNode.AppendChild(stratWarfareMove.Serialise(xml));
            nodeToReturn.AppendChild(StratWarfareMoveNode);

            return nodeToReturn;
        }

        public new static ClientMessageDoStrategicUBoatWarfareReturn Deserialise(System.Xml.XmlNode node)
        {
            StratWarfareMove stratWarfareMove = null;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "StratWarfareMove")
                {
                    stratWarfareMove = (StratWarfareMove)StratWarfareMove.Deserialise(childNode.ChildNodes[0]);
                }
            }

            return new ClientMessageDoStrategicUBoatWarfareReturn(stratWarfareMove);
        }
    };

    class ClientMessageProductionMovesReturn : ClientMessage
    {
        public List<ProductionMove> listOfProductionMoves;

        public ClientMessageProductionMovesReturn(List<ProductionMove> listOfProductionMoves)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.ProductionMovesReturn;
            if (listOfProductionMoves != null)
                this.listOfProductionMoves = new List<ProductionMove>(listOfProductionMoves);
            else
                this.listOfProductionMoves = new List<ProductionMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageProductionMovesReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode ListOfProductionMovesNode = xml.CreateElement("ListOfProductionMoves");
            foreach (ProductionMove productionMove in listOfProductionMoves)
            {
                System.Xml.XmlNode ProductionMoveNode = xml.CreateElement("ProductionMove");
                ProductionMoveNode.AppendChild(productionMove.Serialise(xml));
                ListOfProductionMovesNode.AppendChild(ProductionMoveNode);
            }
            nodeToReturn.AppendChild(ListOfProductionMovesNode);

            return nodeToReturn;
        }

        public new static ClientMessageProductionMovesReturn Deserialise(System.Xml.XmlNode node)
        {
            List<ProductionMove> listOfProductionMoves = new List<ProductionMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ListOfProductionMoves")
                {
                    foreach (System.Xml.XmlNode productionMoveNode in childNode)
                    {
                        listOfProductionMoves.Add((ProductionMove)ProductionMove.Deserialise(productionMoveNode.ChildNodes[0]));
                    }
                }
            }

            return new ClientMessageProductionMovesReturn(listOfProductionMoves);
        }
    };

    class ClientMessageBoolReturn : ClientMessage
    {
        public bool returnValue;

        public ClientMessageBoolReturn(bool returnValue)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.boolReturn;
            this.returnValue = returnValue;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageBoolReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode ReturnValueNode = xml.CreateElement("ReturnValue");
            ReturnValueNode.InnerText = returnValue.ToString();
            nodeToReturn.AppendChild(ReturnValueNode);

            return nodeToReturn;
        }

        public new static ClientMessageBoolReturn Deserialise(System.Xml.XmlNode node)
        {
            bool returnValue = false;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ReturnValue")
                {
                    returnValue = bool.Parse(childNode.InnerText);
                }
            }

            return new ClientMessageBoolReturn(returnValue);
        }
    };

    class ClientMessageMovesReturn : ClientMessage
    {
        public List<Move> listOfMoves;

        public ClientMessageMovesReturn(List<Move> listOfMoves)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.MovesReturn;
            if (listOfMoves != null)
                this.listOfMoves = new List<Move>(listOfMoves);
            else
                this.listOfMoves = new List<Move>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageMovesReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode MovesNode = xml.CreateElement("ListOfMoves");
            foreach (Move move in listOfMoves)
            {
                System.Xml.XmlNode moveNode = xml.CreateElement("Move");
                moveNode.AppendChild(move.Serialise(xml));
                MovesNode.AppendChild(moveNode);
            }
            nodeToReturn.AppendChild(MovesNode);

            return nodeToReturn;
        }

        public new static ClientMessageMovesReturn Deserialise(System.Xml.XmlNode node)
        {
            List<Move> listOfMoves = new List<Move>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ListOfMoves")
                {
                    foreach (System.Xml.XmlNode moveNode in childNode)
                    {
                        listOfMoves.Add((Move)Move.Deserialise(moveNode.ChildNodes[0]));
                    }
                }
            }

            return new ClientMessageMovesReturn(listOfMoves);
        }
    };

    class ClientMessageAskForGSUCombatCasualtiesReturn : ClientMessage
    {
        public Dictionary<MapInfo.CountryID, int> listOfGSUCombatCasualties;

        public ClientMessageAskForGSUCombatCasualtiesReturn(Dictionary<MapInfo.CountryID, int> listOfGSUCombatCasualties)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForGSUCombatCasualtiesReturn;
            if (listOfGSUCombatCasualties != null)
                this.listOfGSUCombatCasualties = new Dictionary<MapInfo.CountryID, int>(listOfGSUCombatCasualties);
            else
                this.listOfGSUCombatCasualties = new Dictionary<MapInfo.CountryID, int>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskForGSUCombatCasualtiesReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode ListOfGSUCombatCasualtiesNode = xml.CreateElement("ListOfGSUCombatCasualties");
            foreach (MapInfo.CountryID country in listOfGSUCombatCasualties.Keys)
            {
                System.Xml.XmlNode GSUCombatCasualtyNode = xml.CreateElement("GSUCombatCasualty");
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.listOfGSUCombatCasualties[country].ToString();
                GSUCombatCasualtyNode.Attributes.Append(countryAttr);
                GSUCombatCasualtyNode.Attributes.Append(numberAttr);
                ListOfGSUCombatCasualtiesNode.AppendChild(GSUCombatCasualtyNode);
            }
            nodeToReturn.AppendChild(ListOfGSUCombatCasualtiesNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskForGSUCombatCasualtiesReturn Deserialise(System.Xml.XmlNode node)
        {
            Dictionary<MapInfo.CountryID, int> listOfGSUCombatCasualties = new Dictionary<MapInfo.CountryID, int>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "ListOfGSUCombatCasualties")
                {
                    foreach (System.Xml.XmlNode GSUCombatCasualtyNode in childNode)
                    {
                        listOfGSUCombatCasualties.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUCombatCasualtyNode.Attributes["country"].Value), Int32.Parse(GSUCombatCasualtyNode.Attributes["number"].Value));
                    }
                }
            }

            return new ClientMessageAskForGSUCombatCasualtiesReturn(listOfGSUCombatCasualties);
        }
    };

    class ClientMessageAskForBreakThroughOptionReturn : ClientMessage
    {
        public GameController.breakThroughSelection breakThroughSelection;

        public ClientMessageAskForBreakThroughOptionReturn(GameController.breakThroughPhaseType breakthroughPhase, List<MapInfo.CountryID> specialActionsSpent)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForBreakThroughOptionReturn;
            breakThroughSelection = new GameController.breakThroughSelection();
            breakThroughSelection.breakthroughPhase = breakthroughPhase;
            if (specialActionsSpent != null)
                breakThroughSelection.specialActionsSpent = new List<MapInfo.CountryID>(specialActionsSpent);
            else
                breakThroughSelection.specialActionsSpent = new List<MapInfo.CountryID>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskForBreakThroughOptionReturn";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("BreakthroughPhase");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.breakThroughPhaseType), this.breakThroughSelection.breakthroughPhase);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("SpecialActionsSpent");
            foreach (MapInfo.CountryID country in this.breakThroughSelection.specialActionsSpent)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                nodeToAdd.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ClientMessageAskForBreakThroughOptionReturn Deserialise(System.Xml.XmlNode node)
        {
            GameController.breakThroughPhaseType breakthroughPhase = GameController.breakThroughPhaseType.BreakthroughCombat;
            List<MapInfo.CountryID> specialActionsSpent = new List<MapInfo.CountryID>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "BreakthroughPhase")
                {
                    breakthroughPhase = (GameController.breakThroughPhaseType)Enum.Parse(typeof(GameController.breakThroughPhaseType), childNode.InnerText);
                }

                if (childNode.Name == "SpecialActionsSpent")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            specialActionsSpent.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
            }

            return new ClientMessageAskForBreakThroughOptionReturn(breakthroughPhase, specialActionsSpent);
        }
    };

    class ClientMessageAskAttackerToAssignLosses : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType attackingPlayer;
        private MapInfo.RegionID battleRegionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private int numInfantryLosses;
        private int numArmorLosses;
        private bool counterAttack;
        private List<MapInfo.CountryID> countriesSpendingSAInBattle;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageAskAttackerToAssignLosses(GameController.playerType attackingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAInBattle, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskAttackerToAssignLosses;
            this.attackingPlayer = attackingPlayer;
            this.battleRegionID = battleRegionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.numInfantryLosses = numInfantryLosses;
            this.numArmorLosses = numArmorLosses;
            this.counterAttack = counterAttack;
            if (countriesSpendingSAInBattle != null)
                this.countriesSpendingSAInBattle = new List<MapInfo.CountryID>(countriesSpendingSAInBattle);
            else
                this.countriesSpendingSAInBattle = new List<MapInfo.CountryID>();
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "AskAttackerToAssignLosses";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode AttackingPlayerNode = xml.CreateElement("AttackingPlayer");
            AttackingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), attackingPlayer);
            nodeToReturn.AppendChild(AttackingPlayerNode);

            System.Xml.XmlNode BattleRegionIDNode = xml.CreateElement("BattleRegionID");
            BattleRegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), battleRegionID);
            nodeToReturn.AppendChild(BattleRegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode NumInfantryLossesNode = xml.CreateElement("NumInfantryLosses");
            NumInfantryLossesNode.InnerText = numInfantryLosses.ToString();
            nodeToReturn.AppendChild(NumInfantryLossesNode);

            System.Xml.XmlNode NumArmorLossesNode = xml.CreateElement("NumArmorLosses");
            NumArmorLossesNode.InnerText = numArmorLosses.ToString();
            nodeToReturn.AppendChild(NumArmorLossesNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode CountriesSpendingSAInBattleNode = xml.CreateElement("CountriesSpendingSAInBattle");
            foreach (MapInfo.CountryID country in countriesSpendingSAInBattle)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSAInBattleNode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSAInBattleNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskAttackerToAssignLosses Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType attackingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID battleRegionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            int numInfantryLosses = 0;
            int numArmorLosses = 0;
            bool counterAttack = false;
            List<MapInfo.CountryID> countriesSpendingSAInBattle = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "AttackingPlayer")
                    attackingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "BattleRegionID")
                    battleRegionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "NumInfantryLosses")
                    numInfantryLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumArmorLosses")
                    numArmorLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CountriesSpendingSAInBattle")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            countriesSpendingSAInBattle.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageAskAttackerToAssignLosses(attackingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken);
        }

        private Dictionary<PlayingPiece, int> AttackerAssignLossesServerCallback(GameController server)
        {
            return server.AskAttackerToAssignLosses(attackingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            Dictionary<PlayingPiece, int> losses;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                losses = (Dictionary<PlayingPiece, int>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerAssignLossesCallback(AttackerAssignLossesServerCallback), new object[] { server });
            }
            else
                losses = server.AskAttackerToAssignLosses(attackingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken);

            return new ServerMessageAssignLossesReturn(losses);
        }
    };

    class ClientMessageDetermineStrategicWarInterception : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType player;

        public ClientMessageDetermineStrategicWarInterception(GameController.playerType player)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.DetermineStrategicWarInterception;
            this.player = player;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageDetermineStrategicWarInterception";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode PlayerNode = xml.CreateElement("Player");
            PlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerNode);

            return nodeToReturn;
        }

        public new static ClientMessageDetermineStrategicWarInterception Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
            }

            return new ClientMessageDetermineStrategicWarInterception(player);
        }

        private bool DetermineStrategicWarInterceptionCallback(GameController server)
        {
            return server.DetermineStrategicWarInterception(player);
        }

        public ServerMessage CallGameController(GameController server)
        {
            bool returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (bool)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerBoolCallback(DetermineStrategicWarInterceptionCallback), new object[] { server });
            }
            else
                returnValue = server.DetermineStrategicWarInterception(player);

            return new ServerMessageAssignBoolReturn(returnValue);
        }
    };

    class ClientMessageAskForNewCountryDeployment : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType player;
        private MapInfo.CountryID country;

        public ClientMessageAskForNewCountryDeployment(GameController.playerType player, MapInfo.CountryID country)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForNewCountryDeployment;
            this.player = player;
            this.country = country;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskForNewCountryDeployment";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode PlayerNode = xml.CreateElement("Player");
            PlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerNode);

            System.Xml.XmlNode CountryNode = xml.CreateElement("Country");
            CountryNode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
            nodeToReturn.AppendChild(CountryNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskForNewCountryDeployment Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            MapInfo.CountryID country = MapInfo.CountryID.BalticStates;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "Country")
                    country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), childNode.InnerText);
            }

            return new ClientMessageAskForNewCountryDeployment(player, country);
        }

        private List<DeploymentMove> AskForNewCountryDeploymentCallback(GameController server)
        {
            return server.AskForNewCountryDeployment(player, country);
        }

        public ServerMessage CallGameController(GameController server)
        {
            List<DeploymentMove> returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (List<DeploymentMove>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerDeploymentMovesCallback(AskForNewCountryDeploymentCallback), new object[] { server });
            }
            else
                returnValue = server.AskForNewCountryDeployment(player, country);

            return new ServerMessageDeploymentMovesReturn(returnValue);
        }
    };

    class ClientMessageAskForNavalInterception : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType player;
        private SeaMoveOperationalMove seaMove;

        public ClientMessageAskForNavalInterception(GameController.playerType player, SeaMoveOperationalMove seaMove)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForNavalInterception;
            this.player = player;
            this.seaMove = seaMove;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskForNavalInterception";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode PlayerNode = xml.CreateElement("Player");
            PlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(PlayerNode);

            System.Xml.XmlNode SeaMoveNode = xml.CreateElement("SeaMove");
            SeaMoveNode.AppendChild(seaMove.Serialise(xml));
            nodeToReturn.AppendChild(SeaMoveNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskForNavalInterception Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            SeaMoveOperationalMove seaMove = null;

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "Player")
                    player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "SeaMove")
                    seaMove = (SeaMoveOperationalMove)Move.Deserialise(childNode.FirstChild);
            }

            return new ClientMessageAskForNavalInterception(player, seaMove);
        }

        private bool AskForNavalInterceptionCallback(GameController server)
        {
            return server.AskForNavalInterception(player, seaMove);
        }

        public ServerMessage CallGameController(GameController server)
        {
            bool returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (bool)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerBoolCallback(AskForNavalInterceptionCallback), new object[] { server });
            }
            else
                returnValue = server.AskForNavalInterception(player, seaMove);

            return new ServerMessageAssignBoolReturn(returnValue);
        }
    };

    class ClientMessageReportForNavalInterception : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType player;
        private MapInfo.RegionID regionID;
        private int numFriendlyHitsOn6;
        private int numFriendlyHitsOn56;
        private int numEnemyHitsOn6;
        private int numEnemyHitsOn56;
        private List<PlayingPiece> piecesTransported;
        private List<PlayingPiece> piecesLost;

        public ClientMessageReportForNavalInterception(GameController.playerType player, MapInfo.RegionID regionID, int numFriendlyHitsOn6, int numFriendlyHitsOn56, int numEnemyHitsOn6, int numEnemyHitsOn56, List<PlayingPiece> piecesTransported, List<PlayingPiece> piecesLost)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForNavalInterception;
            this.player = player;
            this.regionID = regionID;
            this.numFriendlyHitsOn6 = numFriendlyHitsOn6;
            this.numFriendlyHitsOn56 = numFriendlyHitsOn56;
            this.numEnemyHitsOn6 = numEnemyHitsOn6;
            this.numEnemyHitsOn56 = numEnemyHitsOn56;
            if (piecesTransported != null)
                this.piecesTransported = new List<PlayingPiece>(piecesTransported);
            else
                this.piecesTransported = new List<PlayingPiece>();
            if (piecesLost != null)
                this.piecesLost = new List<PlayingPiece>(piecesLost);
            else
                this.piecesLost = new List<PlayingPiece>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ServerMessage");
            System.Xml.XmlAttribute serverMessageTypeAttr = xml.CreateAttribute("ServerMessageType");
            serverMessageTypeAttr.Value = "ClientMessageReportForNavalInterception";
            nodeToReturn.Attributes.Append(serverMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("Player");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), player);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumFriendlyHitsOn6");
            nodeToAdd.InnerText = numFriendlyHitsOn6.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumFriendlyHitsOn56");
            nodeToAdd.InnerText = numFriendlyHitsOn56.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumEnemyHitsOn6");
            nodeToAdd.InnerText = numEnemyHitsOn6.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("NumEnemyHitsOn56");
            nodeToAdd.InnerText = numEnemyHitsOn56.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("PiecesTransported");
            foreach (PlayingPiece playingPiece in piecesTransported)
            {
                System.Xml.XmlNode pieceNode = xml.CreateElement("PlayingPiece");
                if(playingPiece is Block)
                {
                    pieceNode.AppendChild(((Block)playingPiece).Serialise(xml));
                }
                else if(playingPiece is GroundSupportUnit)
                {
                    pieceNode.AppendChild(((GroundSupportUnit)playingPiece).Serialise(xml));
                }
                
                nodeToAdd.AppendChild(pieceNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("PiecesLost");
            foreach (PlayingPiece playingPiece in piecesLost)
            {
                System.Xml.XmlNode pieceNode = xml.CreateElement("PlayingPiece");
                if (playingPiece is Block)
                {
                    pieceNode.AppendChild(((Block)playingPiece).Serialise(xml));
                }
                else if (playingPiece is GroundSupportUnit)
                {
                    pieceNode.AppendChild(((GroundSupportUnit)playingPiece).Serialise(xml));
                }
                nodeToAdd.AppendChild(pieceNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ClientMessageReportForNavalInterception Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType player = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            int numFriendlyHitsOn6 = 0;
            int numFriendlyHitsOn56 = 0;
            int numEnemyHitsOn6 = 0;
            int numEnemyHitsOn56 = 0;
            List<PlayingPiece> piecesTransported = new List<PlayingPiece>();
            List<PlayingPiece> piecesLost = new List<PlayingPiece>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "Player":
                        player = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "RegionID":
                        regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                        break;
                    case "NumFriendlyHitsOn6":
                        numFriendlyHitsOn6 = Int32.Parse(childNode.InnerText);
                        break;
                    case "NumFriendlyHitsOn56":
                        numFriendlyHitsOn56 = Int32.Parse(childNode.InnerText);
                        break;
                    case "NumEnemyHitsOn6":
                        numEnemyHitsOn6 = Int32.Parse(childNode.InnerText);
                        break;
                    case "NumEnemyHitsOn56":
                        numEnemyHitsOn56 = Int32.Parse(childNode.InnerText);
                        break;
                    case "PiecesTransported":
                        foreach (System.Xml.XmlNode PieceNode in childNode)
                        {
                            if (PieceNode.Name == "PlayingPiece")
                            {
                                piecesTransported.Add(PlayingPiece.Deserialise(PieceNode.ChildNodes[0]));
                            }
                        }
                        break;
                    case "PiecesLost":
                        foreach (System.Xml.XmlNode PieceNode in childNode)
                        {
                            if (PieceNode.Name == "PlayingPiece")
                            {
                                piecesLost.Add(PlayingPiece.Deserialise(PieceNode.ChildNodes[0]));
                            }
                        }
                        break;
                }
            }

            return new ClientMessageReportForNavalInterception(player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost);
        }

        private bool ReportForNavalInterceptionCallback(GameController server)
        {
            return server.ReportNavalInterception(player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost);
        }

        public ServerMessage CallGameController(GameController server)
        {
            bool returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (bool)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerBoolCallback(ReportForNavalInterceptionCallback), new object[] { server });
            }
            else
                returnValue = server.ReportNavalInterception(player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost);

            return new ServerMessageAssignBoolReturn(returnValue);
        }
    };

    class ClientMessageAskDefenderForDefenderOptions : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private bool selectGSUs;
        private bool breakThroughCombat;
        private bool assault;
        private List<MapInfo.CountryID> countriesSpendingSA;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageAskDefenderForDefenderOptions(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool selectGSUs, bool breakThroughCombat, bool assault, List<MapInfo.CountryID> countriesSpendingSA, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskDefenderForDefenderOptions;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            this.selectGSUs = selectGSUs;
            this.breakThroughCombat = breakThroughCombat;
            this.assault = assault;
            if (countriesSpendingSA != null)
                this.countriesSpendingSA = new List<MapInfo.CountryID>(countriesSpendingSA);
            else
                this.countriesSpendingSA = new List<MapInfo.CountryID>();
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskDefenderForDefenderOptions";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode RegionIDNode = xml.CreateElement("RegionID");
            RegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(RegionIDNode);

            System.Xml.XmlNode SelectGSUsNode = xml.CreateElement("SelectGSUs");
            SelectGSUsNode.InnerText = selectGSUs.ToString();
            nodeToReturn.AppendChild(SelectGSUsNode);

            System.Xml.XmlNode BreakThroughCombatNode = xml.CreateElement("BreakThroughCombat");
            BreakThroughCombatNode.InnerText = breakThroughCombat.ToString();
            nodeToReturn.AppendChild(BreakThroughCombatNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode CountriesSpendingSANode = xml.CreateElement("CountriesSpendingSA");
            foreach (MapInfo.CountryID country in countriesSpendingSA)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSANode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSANode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskDefenderForDefenderOptions Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            bool selectGSUs = false;
            bool breakThroughCombat = false;
            bool assault = false;
            List<MapInfo.CountryID> countriesSpendingSA = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "SelectGSUs")
                    selectGSUs = bool.Parse(childNode.InnerText);
                if (childNode.Name == "BreakThroughCombat")
                    breakThroughCombat = bool.Parse(childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CountriesSpendingSA")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            countriesSpendingSA.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageAskDefenderForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken);
        }

        private GameController.defenderOptions AskDefenderForDefenderOptionsCallback(GameController server)
        {
            return server.AskDefenderForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            GameController.defenderOptions returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (GameController.defenderOptions)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerDefenderOptionsCallback(AskDefenderForDefenderOptionsCallback), new object[] { server });
            }
            else
                returnValue = server.AskDefenderForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken);

            return new ServerMessageAskForDefenderOptionsReturn(returnValue);
        }
    };

    class ClientMessageAskDefenderForRetreatBeforeCombatMoves : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageAskDefenderForRetreatBeforeCombatMoves(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskDefenderForRetreatBeforeCombatMoves;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskDefenderForRetreatBeforeCombatMoves";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("DefendingPlayer");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMove");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                nodeToAdd.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ClientMessageAskDefenderForRetreatBeforeCombatMoves Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.FirstChild));
                    }
                }
            }

            return new ClientMessageAskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken);
        }

        private List<OperationalMove> AskDefenderForRetreatBeforeCombatMovesCallback(GameController server)
        {
            return server.AskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            List<OperationalMove> returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (List<OperationalMove>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerListOpMovesCallback(AskDefenderForRetreatBeforeCombatMovesCallback), new object[] { server });
            }
            else
                returnValue = server.AskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken);

            return new ServerMessageAskDefenderForRetreatBeforeCombatMovesReturn(returnValue);
        }
    };

    class ClientMessageAskForGSUCombatCasualties : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType playerAssigningCasualties;
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private List<int> defendingDieRolls;
        private List<int> attackingDieRolls;
        private bool breakThrough;
        private List<MapInfo.CountryID> countriesSpendingSA;

        public ClientMessageAskForGSUCombatCasualties(GameController.playerType playerAssigningCasualties, GameController.playerType defendingPlayer, MapInfo.RegionID regionID, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, List<int> defendingDieRolls, List<int> attackingDieRolls, bool breakThrough, List<MapInfo.CountryID> countriesSpendingSA)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskForGSUCombatCasualties;
            this.playerAssigningCasualties = playerAssigningCasualties;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (defendingDieRolls != null)
                this.defendingDieRolls = new List<int>(defendingDieRolls);
            else
                this.defendingDieRolls = new List<int>();
            if (attackingDieRolls != null)
                this.attackingDieRolls = new List<int>(attackingDieRolls);
            else
                this.attackingDieRolls = new List<int>();
            this.breakThrough = breakThrough;
            if (countriesSpendingSA != null)
                this.countriesSpendingSA = new List<MapInfo.CountryID>(countriesSpendingSA);
            else
                this.countriesSpendingSA = new List<MapInfo.CountryID>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskForGSUCombatCasualties";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode nodeToAdd = xml.CreateElement("PlayerAssigningCasualties");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), playerAssigningCasualties);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("DefendingPlayer");
            nodeToAdd.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("RegionID");
            nodeToAdd.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                nodeToAdd.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                nodeToAdd.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("DefendingDieRolls");
            foreach (int dieRoll in this.defendingDieRolls)
            {
                System.Xml.XmlNode DieRollNode = xml.CreateElement("DieRoll");
                DieRollNode.InnerText = dieRoll.ToString();
                nodeToAdd.AppendChild(DieRollNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("AttackingDieRolls");
            foreach (int dieRoll in this.attackingDieRolls)
            {
                System.Xml.XmlNode DieRollNode = xml.CreateElement("DieRoll");
                DieRollNode.InnerText = dieRoll.ToString();
                nodeToAdd.AppendChild(DieRollNode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("BreakThrough");
            nodeToAdd.InnerText = breakThrough.ToString();
            nodeToReturn.AppendChild(nodeToAdd);

            nodeToAdd = xml.CreateElement("CountriesSpendingSA");
            foreach (MapInfo.CountryID country in countriesSpendingSA)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                nodeToAdd.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(nodeToAdd);

            return nodeToReturn;
        }

        public new static ClientMessageAskForGSUCombatCasualties Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType playerAssigningCasualties = GameController.playerType.AlliedPlayer;
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.Albania;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            List<int> defendingDieRolls = new List<int>();
            List<int> attackingDieRolls = new List<int>();
            bool breakThrough = false;
            List<MapInfo.CountryID> countriesSpendingSA = new List<MapInfo.CountryID>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                switch (childNode.Name)
                {
                    case "PlayerAssigningCasualties":
                        playerAssigningCasualties = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "DefendingPlayer":
                        defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                        break;
                    case "DefendingGSUSelections":
                        foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                        {
                            defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                        }
                        break;
                    case "AttackingGSUSelections":
                        foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                        {
                            attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                        }
                        break;
                    case "DefendingDieRolls":
                        foreach (System.Xml.XmlNode DieRollNode in childNode)
                        {
                            defendingDieRolls.Add(Int32.Parse(DieRollNode.InnerText));
                        }
                        break;
                    case "AttackingDieRolls":
                        foreach (System.Xml.XmlNode DieRollNode in childNode)
                        {
                            attackingDieRolls.Add(Int32.Parse(DieRollNode.InnerText));
                        }
                        break;
                    case "CountriesSpendingSA":
                        foreach (System.Xml.XmlNode countryNode in childNode)
                        {
                            if (countryNode.Name == "CountrySpendingSA")
                            {
                                countriesSpendingSA.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                            }
                        }
                        break;
                    case "RegionID":
                        regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                        break;
                }
            }

            return new ClientMessageAskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA);
        }

        private Dictionary<MapInfo.CountryID, int> AskForGSUCombatCasualtiesCallback(GameController server)
        {
            return server.AskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA);
        }

        public ServerMessage CallGameController(GameController server)
        {
            Dictionary<MapInfo.CountryID, int> returnValue;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                returnValue = (Dictionary<MapInfo.CountryID, int>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerGSUCombatCasualtiesCallback(AskForGSUCombatCasualtiesCallback), new object[] { server });
            }
            else
                returnValue = server.AskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA);

            return new ServerMessageAskForGSUCombatCasualtiesReturn(returnValue);
        }
    };

    class ClientMessageDoDefenderCombat : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private bool counterAttack;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageDoDefenderCombat(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.DoDefenderCombat;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.counterAttack = counterAttack;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageDoDefenderCombat";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode RegionIDNode = xml.CreateElement("RegionID");
            RegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(RegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ClientMessageDoDefenderCombat Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            bool counterAttack = false;
            List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageDoDefenderCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, combatMovesAlreadyTaken);
        }

        private Dictionary<PlayingPiece, int> DoDefenderCombatCallback(GameController server)
        {
            return server.DoDefenderCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            Dictionary<PlayingPiece, int> losses;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                losses = (Dictionary<PlayingPiece, int>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerAssignLossesCallback(DoDefenderCombatCallback), new object[] { server });
            }
            else
                losses = server.DoDefenderCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, combatMovesAlreadyTaken);

            return new ServerMessageAssignLossesReturn(losses);
        }
    };

    class ClientMessageDoDefenderBreakThroughCombat : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID regionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private bool counterAttack;
        private List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageDoDefenderBreakThroughCombat(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.DoDefenderCombat;
            this.defendingPlayer = defendingPlayer;
            this.regionID = regionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.counterAttack = counterAttack;
            if (countriesSpendingSAForBreakThroughCombat != null)
                this.countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>(countriesSpendingSAForBreakThroughCombat);
            else
                this.countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>();
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageDoDefenderBreakThroughCombat";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode RegionIDNode = xml.CreateElement("RegionID");
            RegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), regionID);
            nodeToReturn.AppendChild(RegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode CountriesSpendingSAForBreakThroughCombatNode = xml.CreateElement("CountriesSpendingSAForBreakThroughCombat");
            foreach (MapInfo.CountryID country in countriesSpendingSAForBreakThroughCombat)
            {
                System.Xml.XmlNode CountrySpendingSANode = xml.CreateElement("CountrySpendingSA");
                CountrySpendingSANode.InnerText = Enum.GetName(typeof(MapInfo.CountryID), country);
                CountriesSpendingSAForBreakThroughCombatNode.AppendChild(CountrySpendingSANode);
            }
            nodeToReturn.AppendChild(CountriesSpendingSAForBreakThroughCombatNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ClientMessageDoDefenderBreakThroughCombat Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID regionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            bool counterAttack = false;
            List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat = new List<MapInfo.CountryID>();
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "RegionID")
                    regionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CountriesSpendingSAForBreakThroughCombat")
                {
                    foreach (System.Xml.XmlNode countryNode in childNode)
                    {
                        if (countryNode.Name == "CountrySpendingSA")
                        {
                            countriesSpendingSAForBreakThroughCombat.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), countryNode.InnerText));
                        }
                    }
                }
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageDoDefenderBreakThroughCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken);
        }

        private Dictionary<PlayingPiece, int> DoDefenderBreakThroughCombatCallback(GameController server)
        {
            return server.DoDefenderBreakThroughCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            Dictionary<PlayingPiece, int> losses;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                losses = (Dictionary<PlayingPiece, int>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerAssignLossesCallback(DoDefenderBreakThroughCombatCallback), new object[] { server });
            }
            else
                losses = server.DoDefenderBreakThroughCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken);

            return new ServerMessageAssignLossesReturn(losses);
        }
    };

    class ClientMessageAskDefenderToAssignLosses : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID battleRegionID;
        private bool assault;
        private Dictionary<MapInfo.CountryID, int> defendingGSUSelections;
        private Dictionary<MapInfo.CountryID, int> attackingGSUSelections;
        private int numInfantryLosses;
        private int numArmorLosses;
        private bool counterAttack;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageAskDefenderToAssignLosses(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskDefenderToAssignLosses;
            this.defendingPlayer = defendingPlayer;
            this.battleRegionID = battleRegionID;
            this.assault = assault;
            if (defendingGSUSelections != null)
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>(defendingGSUSelections);
            else
                this.defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            if (attackingGSUSelections != null)
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>(attackingGSUSelections);
            else
                this.attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            this.numInfantryLosses = numInfantryLosses;
            this.numArmorLosses = numArmorLosses;
            this.counterAttack = counterAttack;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskDefenderToAssignLosses";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode BattleRegionIDNode = xml.CreateElement("BattleRegionID");
            BattleRegionIDNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), battleRegionID);
            nodeToReturn.AppendChild(BattleRegionIDNode);

            System.Xml.XmlNode AssaultNode = xml.CreateElement("Assault");
            AssaultNode.InnerText = assault.ToString();
            nodeToReturn.AppendChild(AssaultNode);

            System.Xml.XmlNode DefendingGSUSelectionsNode = xml.CreateElement("DefendingGSUSelections");
            foreach (MapInfo.CountryID country in this.defendingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.defendingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                DefendingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(DefendingGSUSelectionsNode);

            System.Xml.XmlNode AttackingGSUSelectionsNode = xml.CreateElement("AttackingGSUSelections");
            foreach (MapInfo.CountryID country in this.attackingGSUSelections.Keys)
            {
                System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("country");
                System.Xml.XmlAttribute numberAttr = xml.CreateAttribute("number");
                System.Xml.XmlNode GSUSelectionNode = xml.CreateElement("GSUSelection");
                countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), country);
                numberAttr.Value = this.attackingGSUSelections[country].ToString();
                GSUSelectionNode.Attributes.Append(countryAttr);
                GSUSelectionNode.Attributes.Append(numberAttr);
                AttackingGSUSelectionsNode.AppendChild(GSUSelectionNode);
            }
            nodeToReturn.AppendChild(AttackingGSUSelectionsNode);

            System.Xml.XmlNode NumInfantryLossesNode = xml.CreateElement("NumInfantryLosses");
            NumInfantryLossesNode.InnerText = numInfantryLosses.ToString();
            nodeToReturn.AppendChild(NumInfantryLossesNode);

            System.Xml.XmlNode NumArmorLossesNode = xml.CreateElement("NumArmorLosses");
            NumArmorLossesNode.InnerText = numArmorLosses.ToString();
            nodeToReturn.AppendChild(NumArmorLossesNode);

            System.Xml.XmlNode CounterAttackNode = xml.CreateElement("CounterAttack");
            CounterAttackNode.InnerText = counterAttack.ToString();
            nodeToReturn.AppendChild(CounterAttackNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskDefenderToAssignLosses Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID battleRegionID = MapInfo.RegionID.AtlanticOcean;
            bool assault = false;
            Dictionary<MapInfo.CountryID, int> defendingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            Dictionary<MapInfo.CountryID, int> attackingGSUSelections = new Dictionary<MapInfo.CountryID, int>();
            int numInfantryLosses = 0;
            int numArmorLosses = 0;
            bool counterAttack = false;
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "BattleRegionID")
                    battleRegionID = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "Assault")
                    assault = bool.Parse(childNode.InnerText);
                if (childNode.Name == "DefendingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        defendingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "AttackingGSUSelections")
                {
                    foreach (System.Xml.XmlNode GSUSelectionNode in childNode)
                    {
                        attackingGSUSelections.Add((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), GSUSelectionNode.Attributes["country"].Value), Int32.Parse(GSUSelectionNode.Attributes["number"].Value));
                    }
                }
                if (childNode.Name == "NumInfantryLosses")
                    numInfantryLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "NumArmorLosses")
                    numArmorLosses = Int32.Parse(childNode.InnerText);
                if (childNode.Name == "CounterAttack")
                    counterAttack = bool.Parse(childNode.InnerText);
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageAskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken);
        }

        private Dictionary<PlayingPiece, int> AskDefenderToAssignLossesCallback(GameController server)
        {
            return server.AskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            Dictionary<PlayingPiece, int> losses;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                losses = (Dictionary<PlayingPiece, int>)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerAssignLossesCallback(AskDefenderToAssignLossesCallback), new object[] { server });
            }
            else
                losses = server.AskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken);

            return new ServerMessageAssignLossesReturn(losses);
        }
    };

    class ClientMessageAskDefenderForCounterAttack : ClientMessage, IGameControllerCaller
    {
        private GameController.playerType defendingPlayer;
        private MapInfo.RegionID battleRegion;
        private List<CombatMove> combatMovesAlreadyTaken;

        public ClientMessageAskDefenderForCounterAttack(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegion, List<CombatMove> combatMovesAlreadyTaken)
        {
            this.serverMessageToReturn = TCPServer.ServerRequestMessage.AskDefenderForCounterAttack;
            this.defendingPlayer = defendingPlayer;
            this.battleRegion = battleRegion;
            if (combatMovesAlreadyTaken != null)
                this.combatMovesAlreadyTaken = new List<CombatMove>(combatMovesAlreadyTaken);
            else
                this.combatMovesAlreadyTaken = new List<CombatMove>();
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ClientMessage");
            System.Xml.XmlAttribute clientMessageTypeAttr = xml.CreateAttribute("ClientMessageType");
            clientMessageTypeAttr.Value = "ClientMessageAskDefenderForCounterAttack";
            nodeToReturn.Attributes.Append(clientMessageTypeAttr);

            System.Xml.XmlNode DefendingPlayerNode = xml.CreateElement("DefendingPlayer");
            DefendingPlayerNode.InnerText = Enum.GetName(typeof(GameController.playerType), defendingPlayer);
            nodeToReturn.AppendChild(DefendingPlayerNode);

            System.Xml.XmlNode BattleRegionNode = xml.CreateElement("BattleRegion");
            BattleRegionNode.InnerText = Enum.GetName(typeof(MapInfo.RegionID), battleRegion);
            nodeToReturn.AppendChild(BattleRegionNode);

            System.Xml.XmlNode CombatMovesAlreadyTakenNode = xml.CreateElement("CombatMovesAlreadyTaken");
            foreach (CombatMove combatMove in combatMovesAlreadyTaken)
            {
                System.Xml.XmlNode CombatMoveNode = xml.CreateElement("CombatMoveNode");
                CombatMoveNode.AppendChild(combatMove.Serialise(xml));
                CombatMovesAlreadyTakenNode.AppendChild(CombatMoveNode);
            }
            nodeToReturn.AppendChild(CombatMovesAlreadyTakenNode);

            return nodeToReturn;
        }

        public new static ClientMessageAskDefenderForCounterAttack Deserialise(System.Xml.XmlNode node)
        {
            GameController.playerType defendingPlayer = GameController.playerType.AlliedPlayer;
            MapInfo.RegionID battleRegion = MapInfo.RegionID.AtlanticOcean;
            List<CombatMove> combatMovesAlreadyTaken = new List<CombatMove>();

            foreach (System.Xml.XmlNode childNode in node)
            {
                if (childNode.Name == "DefendingPlayer")
                    defendingPlayer = (GameController.playerType)Enum.Parse(typeof(GameController.playerType), childNode.InnerText);
                if (childNode.Name == "BattleRegion")
                    battleRegion = (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), childNode.InnerText);
                if (childNode.Name == "CombatMovesAlreadyTaken")
                {
                    foreach (System.Xml.XmlNode CombatMoveNode in childNode)
                    {
                        if (CombatMoveNode.Name == "CombatMoveNode")
                        {
                            combatMovesAlreadyTaken.Add((CombatMove)CombatMove.Deserialise(CombatMoveNode.ChildNodes[0]));
                        }
                    }
                }
            }

            return new ClientMessageAskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken);
        }

        private GameController.defenderCounterAttackOptions AskDefenderForCounterAttackCallback(GameController server)
        {
            return server.AskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken);
        }

        public ServerMessage CallGameController(GameController server)
        {
            GameController.defenderCounterAttackOptions counterAttackOptions;
            if (EuropeEngulfedNETForm.MainForm.InvokeRequired)
            {
                counterAttackOptions = (GameController.defenderCounterAttackOptions)EuropeEngulfedNETForm.MainForm.Invoke(new GameControllerDefenderCounterAttackCallback(AskDefenderForCounterAttackCallback), new object[] { server });
            }
            else
                counterAttackOptions = server.AskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken);

            return new ServerMessageAskDefenderForCounterAttackReturn(counterAttackOptions);
        }
    };
}
